package se.statifyme.client.record;

import se.statifyme.shared.RecordServiceConstants;
import se.statifyme.shared.StringUtils;
import se.thoka.twt.client.utils.TWTLogger;

import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestBuilder.Method;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.rpc.AsyncCallback;

public enum RecordClient {
	INSTANCE;
	
	public enum ContentType {
		JSON("application/json"),
		XML("application/xml");
		
		private final String contentType;
		private ContentType(String contentType) {
			this.contentType = contentType;
		}
		public String getContentType() {
			return contentType;
		}
		public static ContentType fromContentType(String contentType) {
			ContentType result = null;
			for (ContentType ct : values()) {
				if (ct.contentType.equalsIgnoreCase(contentType)) {
					result = ct;
					break;
				}
			}
			if (result == null) {
				throw new IllegalArgumentException("No content type found for value \"" + contentType + "\"");
			}
			return result;
		}
	}
	
//	private static final String SERVICE 			= "service";
	private static final String SLASH 				= "/";
	private static final String CONTENT_TYPE 		= "Content-Type";
	private static final String ACCEPT 				= "Accept";
	
	private ContentType contentType;
	
	private RecordClient() {
		this.contentType = ContentType.JSON;
	}
	
	public ContentType getContentType() {
		return contentType;
	}
	
	public void setContentType(ContentType contentType) {
		if (contentType != null) {
			this.contentType = contentType;
		}
	}
	
	public void delete(String url, final AsyncCallback<String> callback) {
		execute(RequestBuilder.DELETE, url, null, callback);
	}
	
	public void get(String url, final AsyncCallback<String> callback) {
		execute(RequestBuilder.GET, url, null, callback);
	}

	public void post(String url, String data, final AsyncCallback<String> callback) {
		execute(RequestBuilder.POST, url, data, callback);
	}
	
	public void execute(final Method method, final String url, String data, final AsyncCallback<String> callback) {
		RequestBuilder builder = new RequestBuilder(method, url);
		builder.setHeader(CONTENT_TYPE, contentType.getContentType());
		builder.setHeader(ACCEPT, contentType.getContentType());
		try {
			builder.sendRequest(data, new RequestCallback() {
				@Override
				public void onResponseReceived(Request request, Response response) {
					final int statusCode = response.getStatusCode();
					if (statusCode < 400) {
						callback.onSuccess(response.getText());
					} else {
						TWTLogger.log("JSONClient#execute() StatusCode: " + statusCode);
						callback.onFailure(new RequestException("Status: " + response.getStatusText() + " (" + statusCode + ")"));
					}
				}
				@Override
				public void onError(Request request, Throwable caught) {
					callback.onFailure(caught);
				}
			});
		} catch (RequestException caught) {
			callback.onFailure(caught);
		}
	}
	
	public static String buildServiceDeclarationURI(String service) {
		return buildURI(service, RecordServiceConstants.PATH_RECORD_DECLARATION, null);
	}
	
	public static String buildServiceExampleURI(String service) {
		return buildURI(service, RecordServiceConstants.PATH_RECORD_EXAMPLE, null);
	}
	
	public static String buildServiceRecordURI(String service, String id) {
		return buildURI(service, RecordServiceConstants.PATH_RECORD, id);
	}

	public static String getServiceDeclarationsURI() {
		return buildServiceRecordURI("recordtype", null);
	}
	
	private static String buildURI(String service, String entity, String id) {
		String realService = removeSlashes(service);
		if (StringUtils.isBlank(realService)) {
			throw new IllegalArgumentException("Illegal service: " + service);
		}
		String realEntity = removeSlashes(entity);
		if (StringUtils.isBlank(realEntity)) {
			throw new IllegalArgumentException("Illegal entity: " + entity);
		}
		
		StringBuilder builder = new StringBuilder();
		if (!realService.startsWith("rest/")) {
			builder.append("/rest/");
		}
		builder.append(realService);
		builder.append(SLASH);
		builder.append(entity);
		builder.append(SLASH);
		if (StringUtils.isNotBlank(id)) {
			builder.append(id);
		}
		
		return builder.toString();
	}
	
	private static String removeSlashes(String s) {
		if (StringUtils.isNotBlank(s)) {
			if (s.startsWith(SLASH)) {
				s = s.substring(1);
			}
			if (s.endsWith(SLASH)) {
				s = s.substring(0, s.length() - 1);
			}
		}
		
		return s;
	}
	
}
